import getopt
import os.path
import sys
from typing import Dict

import jsonpath2
import pydash
import toml
import ujson as json
import yaml

if __name__ == '__main__':

    from internal import get_internal_logger
    from single_ton import SingleTon
else:
    from .internal import get_internal_logger
    from ys_python.common.base.single_ton import SingleTon

logger = get_internal_logger("config")


@SingleTon
class Config:
    """全局统一的配置管理器

    """

    __cfg_dict: Dict = {}
    __path = ""

    __search_types = [".toml", ".yaml", ".json"]
    __search_dirs = ["", "config", "manifest/config"]

    def __init__(self):
        self.__search_config_path()
        self.load()

    def get(self, json_path: str, default=None):
        path = jsonpath2.Path.parse_str(json_path)
        for m in path.match(self.__cfg_dict):
            return m.current_value
        return default

    def __search_config_path(self):
        # 判断用户是不是输入了配置文件
        self.__path = self.__get_config_path_from_opt()

        if pydash.is_empty(self.__path):
            path_root = os.path.abspath(os.sep)
            d = os.path.abspath("./")  # 搜索的初始路径
            while pydash.is_empty(self.__path):
                self.__path = self.__get_config_file(d)
                d = os.path.dirname(d)
                if os.path.samefile(d, path_root):
                    break

    def __get_config_path_from_opt(self):
        opts = getopt.getopt(sys.argv[1:], "c:")

        for opt in opts[0]:
            if opt[0] == '-c':
                return opt[1].lstrip("=")

        return ""

    def __get_config_file(self, dir: str, filename: str = "config") -> str:
        """
        检查指定路径下的 config 文件是否存在
        - 当前路径下是否存在
        - config 文件夹内是否存在

        Args:
            dir: 要遍历的路径
            filename:

        Returns:
            文件存在返回文件名，否则返回空字符串
        """
        for _sdir in self.__search_dirs:
            p = os.path.join(dir, _sdir, filename)
            if os.path.splitext(p)[-1] == "":
                for t in self.__search_types:
                    if os.path.exists(p + t):
                        return p + t
            elif os.path.exists(p):
                return p

        return ""

    def load(self, path=None):
        """读取配置文件

        Args:
            path: 配置文件路径, 不填充时
        """
        if path is None:
            if pydash.is_empty(self.__path):
                self.__search_config_path()
            else:
                path = self.__path

        if path is None or not os.path.exists(path):
            if pydash.is_empty(path):
                logger.error("未能读取到配置文件！")
            else:
                logger.error("未找到文件：{}".format(path))
            return False

        logger.debug("读取配置文件：{}".format(path))

        ext = os.path.splitext(path)[-1]

        with open(path, encoding="utf8") as f:
            if ext == ".toml":
                self.__cfg_dict = toml.load(f)
            elif ext == ".json":
                self.__cfg_dict = json.load(f)
            elif ext == ".yaml":
                self.__cfg_dict = yaml.safe_load(f)

        logger.debug(f"{self.__cfg_dict}")
        return True

    @property
    def path(self):
        return self.__path


def get_config_value(json_path: str, default=None):
    """从配置文件中获取数据

    Args:
        json_path: 符合jsonPath的数据检索规则
        default: 当检索不到时的默认值

    Return:
        检索到时返回 检索值, 未检索到时返回 default 值
    """
    cfg: Config = Config()
    return cfg.get(json_path, default)


def load_config(path: str):
    """从指定文件重新驾加载配置参数

    Note:
        部分模块参数可能不会更新，最好还是修改配置后重启软件
    """
    cfg: Config = Config()
    return cfg.load(path)


if __name__ == '__main__':
    cfg: Config = Config()
    print(cfg.get("$.app.name"))
